// <editor-fold defaultstate="collapsed" desc="GNU GPLv3 Header">
/*
 * File:   LittleEndianBinaryFileOps.java
 *
 * Copyright (C) 2013 Robert Antoni Buj Gelonch <rbuj@uoc.edu>
 * Copyright (C) 2013 David Megias Jimenez <dmegias@uoc.edu>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
// </editor-fold>
package uoc.libwave;

// <editor-fold defaultstate="collapsed" desc="imports">
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
// </editor-fold>

/**
 * Class that provides methods to read and write little-endian data in Data I/O Streams.
 * <p>
 * In Java, data is stored in big­endian format (also called network order).
 * That is, all data is represented sequentially starting from the most
 * significant bit to the least significant.
 * The read methods (readByte(), readShort(), readInt(), readLong(), readFloat(),
 * and readDouble()) and the corresponding write methods defined by class
 * java.io.DataInputStream and class java.io.DataOutputStream operate only on
 * big­endian data.
 *
 * @author Robert Antoni Buj Gelonch <rbuj@uoc.edu>
 * @version 1.0
 * @since 2013-08-04
 */
class LittleEndianBinaryFileOps {

    /**
     *
     * @since 2013-08-04
     */
    LittleEndianBinaryFileOps() {
    }

    /**
     * Reads an ASCII char from the underlying input stream as one byte.
     *
     * @param dis DataInputStream that points correctly  to the underlying input
     * stream for reading data.
     * @return a char in Big Endian
     * @throws IOException if an input error occurs.
     *
     * @since 2013-08-04
     */
    protected char readAsciiCharLE(DataInputStream dis) throws IOException {
        return (char) readByteLE(dis);
    }

    /**
     * Reads a byte from the underlying input stream as one byte.
     *
     * @param dis DataInputStream that points correctly to the underlying input
     * stream for reading data.
     * @return a byte in Big Endian
     * @throws IOException if an input error occurs.
     *
     * @since 2013-08-04
     */
    protected byte readByteLE(DataInputStream dis) throws IOException {
        return dis.readByte();
    }

    /**
     * Reads a short from the underlying input stream as two bytes, high byte first.
     * <p>
     * This compliance function uses methods provided by class ByteBuffer to
     * extract correctly a short from the original input value. It wraps the
     * input byte array with a ByteBuffer, sets the byte order to little­endian,
     * and extracts the short. The result is stored in the short serialNumber.
     *
     * @param dis DataInputStream that points correctly to the underlying input
     * stream for reading data.
     * @return a short serialNumber
     * @throws IOException if an input error occurs.
     * @see java.nio.ByteBuffer
     *
     * @since 2013-08-04
     */
    protected short readShortLE(DataInputStream dis) throws IOException {
        byte[] buffer = new byte[2];
        dis.read(buffer);
        return ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN).getShort();
    }

    /**
     * Reads an int from the underlying input stream as four bytes, high byte first.
     * <p>
     * This compliance function uses methods provided by class ByteBuffer to
     * extract correctly an int from the original input value. It wraps the input
     * byte array with a ByteBuffer, sets the byte order to little­endian, and
     * extracts the int. The result is stored in the integer serialNumber.
     *
     * @param dis DataInputStream that points correctly to the underlying input
     * stream for reading data.
     * @return an integer serialNumber
     * @throws IOException if an input error occurs.
     * @see java.nio.ByteBuffer
     *
     * @since 2013-08-04
     */
    protected int readLongLE(DataInputStream dis) throws IOException {
        byte[] buffer = new byte[4];
        dis.read(buffer);
        return ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN).getInt();
    }

    /**
     * Writes an ASCII char to the underlying output stream as one byte.
     *
     * @param c
     * @param dos DataOutputStream that points correctly to the underlying output
     * stream for writing data.
     * @throws IOException if an output error occurs.
     *
     * @since 2013-08-04
     */
    protected void writeAsciiCharLE(char c, DataOutputStream dos) throws IOException {
        writeByteLE((byte) c, dos);
    }

    /**
     * Writes a byte to the underlying output stream as one byte.
     *
     * @param b
     * @param dos DataOutputStream that points correctly to the underlying output
     * stream for writing data.
     * @throws IOException if an output error occurs.
     *
     * @since 2013-08-04
     */
    protected void writeByteLE(byte b, DataOutputStream dos) throws IOException {
        dos.writeByte(b);
    }

    /**
     * Writes a short to the underlying output stream as two bytes, low byte first.
     * <p>
     * This compliance method uses the methods provided by class ByteBuffer to
     * convert correctly a short to the target value, a byte array in little
     * endian data format. It allocates two new elements in a byte array on a
     * ByteBuffer, sets the byte order to little­endian, puts the input value
     * and extrats an array of bytes in little­endian data format.
     *
     * @param value
     * @param dos DataOutputStream that points correctly to the underlying output
     * stream for writing data.
     * @throws IOException if an output error occurs.
     * @see java.nio.ByteBuffer
     *
     * @since 2013-08-04
     */
    protected void writeShortLE(short value, DataOutputStream dos) throws IOException {
        ByteBuffer byteBuffer = ByteBuffer.allocate(2);
        byteBuffer.order(ByteOrder.LITTLE_ENDIAN).putShort(value);
        byte[] buffer = byteBuffer.array();
        dos.write(buffer);
    }

    /**
     * Writes an int to the underlying output stream as four bytes, low byte first.
     * <p>
     * This compliance method uses the methods provided by class ByteBuffer to
     * convert correctly an int to the target value, a byte array in little
     * endian data format. It allocates four new elements in a byte array on a 
     * ByteBuffer, sets the byte order to little­endian, puts the input value
     * and extrats an array of bytes in little­endian data format.
     *
     * @param value
     * @param dos DataOutputStream that points correctly to the underlying output
     * stream for writing data.
     * @throws IOException if an output error occurs.
     * @see java.nio.ByteBuffer
     * 
     * @since 2013-08-04
     */
    protected void writeLongLE(int value, DataOutputStream dos) throws IOException {
        ByteBuffer byteBuffer = ByteBuffer.allocate(4);
        byteBuffer.order(ByteOrder.LITTLE_ENDIAN).putInt(value);
        byte[] buffer = byteBuffer.array();
        dos.write(buffer);
    }
}
